import Designer from '@/index';
import { isNumber, toPx } from './base';

/**
 * 位置偏移、旋转及缩放
 */
const transform = (ctx, { translateX = 0, translateY = 0, rotation = 0, scale = 1, origin = { x: 0, y: 0 } } = {}) => {
  // 位置偏移
  ctx.translate(translateX, translateY);
  // 使用原点旋转及缩放，旋转和缩放的顺序很重要，先旋转后缩放，否则会导致图像倾斜
  ctx.translate(origin.x, origin.y);
  // 旋转
  ctx.rotate(rotation * (Math.PI / 180));
  // 缩放
  ctx.scale(scale, scale);
  // 恢复到缩放及旋转前的坐标
  ctx.translate(-origin.x, -origin.y);
};

/**
 * 绘制轮廓
 */
const outline = (
  ctx,
  edges,
  { strokeStyle = Designer.theme, lineWidth = 1, lineDash = [], lineJoin = 'round', opacity = 1 } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.beginPath();
  ctx.strokeStyle = strokeStyle;
  ctx.lineWidth = lineWidth;
  ctx.setLineDash(lineDash);
  ctx.lineJoin = lineJoin;
  edges.forEach(({ o, d }) => (ctx.lineTo(o.x, o.y), ctx.lineTo(d.x, d.y)));
  ctx.closePath();
  ctx.stroke();
  ctx.restore();
};

/**
 * 绘制矩形
 */
const rect = (
  ctx,
  {
    x = 0,
    y = 0,
    width = 0,
    height = 0,
    strokeStyle = Designer.theme,
    lineWidth = 1,
    lineDash = [],
    opacity = 1,
    transformConfig = undefined,
  } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.translate(x, y);
  // 形变
  if (transformConfig) transform(ctx, { origin: { x: width / 2, y: height / 2 }, ...transformConfig });
  ctx.beginPath();
  ctx.strokeStyle = strokeStyle;
  ctx.lineWidth = lineWidth;
  ctx.setLineDash(lineDash);
  ctx.rect(0, 0, width, height);
  ctx.stroke();
  ctx.restore();
};

/**
 * 绘制填充矩形
 */
const fillRect = (
  ctx,
  { x = 0, y = 0, width = 0, height = 0, fillStyle = Designer.theme, opacity = 1, transformConfig = undefined } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.translate(x, y);
  // 形变
  if (transformConfig) transform(ctx, { origin: { x: width / 2, y: height / 2 }, ...transformConfig });
  ctx.fillStyle = fillStyle;
  ctx.fillRect(0, 0, width, height);
  ctx.restore();
};

/**
 * 绘制圆角矩形
 */
const roundRect = (
  ctx,
  {
    x = 0,
    y = 0,
    width = 0,
    height = 0,
    radius = 0,
    color = Designer.theme,
    lineWidth = 1,
    lineDash = [],
    isFill = true,
    opacity = 1,
    transformConfig = undefined,
  } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.translate(x, y);
  // 形变
  if (transformConfig) transform(ctx, { origin: { x: width / 2, y: height / 2 }, ...transformConfig });
  ctx.beginPath();
  ctx.roundRect(0, 0, width, height, radius);
  // ctx.moveTo(radius, 0);
  // // 上边
  // ctx.lineTo(width - radius, 0);
  // // 右上角
  // ctx.arcTo(width, 0, width, radius, radius);
  // // 右边
  // ctx.lineTo(width, height - radius);
  // // 右下角
  // ctx.arcTo(width, height, width - radius, height, radius);
  // // 下边
  // ctx.lineTo(radius, height);
  // // 左下角
  // ctx.arcTo(0, height, 0, height - radius, radius);
  // // 左边
  // ctx.lineTo(0, radius);
  // // 左上角
  // ctx.arcTo(0, 0, radius, 0, radius);
  if (isFill) {
    ctx.fillStyle = color;
    ctx.fill();
  } else {
    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(lineDash);
    ctx.stroke();
  }
  ctx.restore();
};

/**
 * 绘制文本
 */
const text = (
  ctx,
  {
    text = '',
    x = 0,
    y = 0,
    textBaseline = 'middle',
    align = 'left',
    color = 'black',
    letterSpacing = 0,
    fontStyle = 'normal',
    fontVariant = 'normal',
    fontWeight = 'normal',
    fontSize = 12,
    fontFamily = Designer.defaultFontFamily,
    lineWidth = 1,
    lineDash = [],
    isFill = true,
    maxWidth = undefined,
    reserve = true,
    opacity = 1,
    transformConfig = undefined,
  } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.translate(x, y);
  ctx.textBaseline = textBaseline;
  ctx.textAlign = align;
  ctx.letterSpacing = toPx(letterSpacing);
  ctx.font = `${fontStyle} ${fontVariant} ${fontWeight} ${toPx(fontSize)} ${fontFamily}`;
  // 限制文本最大宽度
  if (maxWidth) {
    let temp = '';
    for (const char of text.split('')) {
      temp += char;
      const width = ctx.measureText(temp).width;
      // 文本长度大于最大宽度时截取 文本超出省略号
      if (width > maxWidth) {
        text = temp.slice(0, -2) + '...';
        break;
      }
    }
    // 至少保留首字
    if (text === '...' && reserve) text = temp[0] + text;
  } else maxWidth = ctx.measureText(text).width;
  // 形变
  if (transformConfig) {
    const originX = { left: maxWidth / 2, center: 0, right: -maxWidth / 2 }[align] || 0;
    transform(ctx, { origin: { x: originX, y: 0 }, ...transformConfig });
  }
  if (isFill) {
    ctx.fillStyle = color;
    ctx.fillText(text, 0, 0);
  } else {
    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(lineDash);
    ctx.strokeText(text, 0, 0);
  }
  ctx.restore();
};

/**
 * 绘制圆弧
 */
const arc = (
  ctx,
  {
    x = 0,
    y = 0,
    radius = 0,
    startAngle = 0,
    endAngle = 2 * Math.PI,
    anticlockwise = false,
    color = Designer.theme,
    lineWidth = 1,
    lineDash = [],
    isFill = true,
    opacity = 1,
    transformConfig = undefined,
  } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.translate(x, y);
  // 形变
  if (transformConfig) transform(ctx, { ...transformConfig });
  ctx.beginPath();
  ctx.arc(0, 0, radius, startAngle, endAngle, anticlockwise);
  if (isFill) {
    ctx.fillStyle = color;
    ctx.fill();
  } else {
    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(lineDash);
    ctx.stroke();
  }
  ctx.restore();
};

/**
 * 绘制线段
 */
const line = (
  ctx,
  {
    o = { x: 0, y: 0 },
    d = { x: 0, y: 0 },
    strokeStyle = Designer.theme,
    lineWidth = 1,
    lineDash = [],
    lineCap = 'butt',
    opacity = 1,
  } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.beginPath();
  ctx.strokeStyle = strokeStyle;
  ctx.lineWidth = lineWidth;
  ctx.setLineDash(lineDash);
  ctx.lineCap = lineCap;
  ctx.moveTo(o.x, o.y);
  ctx.lineTo(d.x, d.y);
  ctx.stroke();
  ctx.restore();
};

/**
 * 绘制图片
 */
const image = (
  ctx,
  { image = null, x = 0, y = 0, width = 0, height = 0, clipping = null, opacity = 1, transformConfig = undefined } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.translate(x, y);
  // 形变
  if (transformConfig) transform(ctx, { origin: { x: width / 2, y: height / 2 }, ...transformConfig });
  try {
    // 有裁剪信息
    if (clipping) {
      const { x: sx, y: sy, w: sw, h: sh } = clipping;
      // 裁剪信息有误
      if (!isNumber(sx) || !isNumber(sy) || !isNumber(sw) || !isNumber(sh)) {
        console.warn('图片裁剪数据有误或缺失！已渲染未裁剪的完整图片。');
        ctx.drawImage(image, 0, 0, width, height);
      } else {
        ctx.drawImage(image, sx, sy, sw, sh, 0, 0, width, height);
      }
    }
    // 没有裁剪信息
    else ctx.drawImage(image, 0, 0, width, height);
  } catch (error) {
    throw new Error(error);
  } finally {
    ctx.restore();
  }
};

/**
 * 绘制三角箭头
 */
const arrows = (
  ctx,
  {
    x = 0,
    y = 0,
    base = 0,
    height = 0,
    color = Designer.theme,
    lineWidth = 1,
    lineDash = [],
    isFill = true,
    opacity = 1,
    transformConfig = undefined,
  } = {},
) => {
  ctx.save();
  ctx.globalAlpha = opacity;
  ctx.translate(x, y);
  // 形变
  if (transformConfig) transform(ctx, { ...transformConfig });
  ctx.beginPath();
  ctx.moveTo(0, -height / 2);
  ctx.lineTo(base / 2, height / 2);
  ctx.lineTo(-base / 2, height / 2);
  ctx.closePath();
  if (isFill) {
    ctx.fillStyle = color;
    ctx.fill();
  } else {
    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(lineDash);
    ctx.stroke();
  }
  ctx.restore();
};

export default {
  // 绘制轮廓
  outline,
  // 绘制矩形
  rect,
  // 绘制填充矩形
  fillRect,
  // 绘制圆角矩形
  roundRect,
  // 绘制文本
  text,
  // 绘制圆弧
  arc,
  // 绘制线段
  line,
  // 绘制图片
  image,
  // 绘制三角箭头
  arrows,
};
